EKS Auto Mode で Network Policy を利用してみる #AWSreInvent

EKS Auto Mode で Network Policy を利用してみる #AWSreInvent

先日 EKS Auto Mode が追加されました。

https://aws.amazon.com/jp/blogs/aws/streamline-kubernetes-cluster-management-with-new-amazon-eks-auto-mode/?trk=d57158fd-77e3-423f-9e1e-005fd2a64d89&sc_channel=el

上記公式ブログの中に、セットアップ不要で Network Policy を利用できるような記載がありました。

EKS Auto Mode enables the following Kubernetes capabilities in your EKS cluster:
Compute auto scaling and management
Application load balancing management
Pod and service networking and network policies
Cluster DNS and GPU support
Block storage volume support

公式ドキュメントでも、VPC CNI plugin をインストールしたり管理しなくてよくなる旨の記載があります。

With Amazon EKS Auto Mode, you don’t need to install or upgrade networking add-ons. Auto Mode includes pod networking and load balancing capabilities.
Amazon VPC CNI

実際にどのくらい楽になるのか試してみました!

Network Policy とは?

Kubernetes 内の通信制御を行うためのリソースです。
下記のような Kubernetes リソースを作成して利用します。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Network Policies

セキュリティレベルの異なるリソースがデプロイされているのであれば、積極的に利用したい機能になります。
EKS Best Practices Guides でも不要な通信は遮断することを推奨されています。

As with RBAC policies, it is recommended to follow least privileged access principles with network policies. Start by creating a deny all policy that restricts all inbound and outbound traffic with in a namespace.
Getting Started with Network Policies - Follow Principle of Least Privilege

EKS における Network Policy

Network Policy 自体、EKS にデフォルトでインストールされている VPC CNI plugin で利用できるようになったのは去年の 8 月です。

https://aws.amazon.com/jp/blogs/containers/amazon-vpc-cni-now-supports-kubernetes-network-policies/

The VPC CNI is the default networking plugin supported by EKS and hence is the focus of the guide.
Amazon EKS Best Practices Guide for Networking

この以前は VPC CNI plugin 以外のサードパーティーの Plugin をインストールして利用する必要がありました。

[補足]
Kubernetes はコンテナネットワークに必要な仕様を Container Network Interface として定めており、こちらに適合したプラグインであれば、VPC CNI plugin 以外でも利用することができます。ただし、不要なコンポーネントをインストールすると管理負荷も上がるので VPC CNI を AWS が管理してくれるなら嬉しいですし、VPC CNI plugin で利用可能な Pod のセキュリティグループを併用することで、Pod と AWS リソースの通信制御を行いやすくなります(ただし、Kubernetes 内の通信制御は Network Policy の方が扱いやすいので併用が推奨されます)。

Amazon VPC CNI in IPv4 mode offers a powerful feature known as Security groups for pods. This feature enables you to use Amazon EC2 security groups to define rules governing inbound and outbound network traffic to and from the pods deployed on your nodes. By using a combination of security groups for pods and network policies, you can enhance your security posture.
Amazon VPC CNI now supports Kubernetes Network Policies

また、VPC CNI plugin で Network Policy を扱うことができるようになっても、個別に VPC CNI アドオンをインストールして設定する必要がありました。
利用する Kubernetes バージョンに対応しているアドオンを選択して、IAM ロールを作成して、アドオンの Configuration(enableNetworkPolicy: "true")をしつつインストールする必要があります。

https://docs.aws.amazon.com/eks/latest/userguide/cni-network-policy-configure.html

特にバージョンに関しては、Kubernetes のバージョンアップの度に気にする必要があるため、こういったアドオン管理が積もり重なると運用コストに響いてきます。
こちらが 良い感じに低減されれば、より Kubernetes 上のアプリケーション開発等に工数を割くことができるようになります!

セットアップ

公式ドキュメントは下記になるので、こちらに従って進めていきます。

https://docs.aws.amazon.com/eks/latest/userguide/auto-net-pol.html

Auto Mode の EKS を eksctl で作成します。

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: test-cluster
  region: ap-northeast-1
  version: "1.31"

iam:
  withOIDC: true

cloudWatch:
  clusterLogging:
    enableTypes:
      - "audit"
      - "authenticator"
      - "controllerManager"
      - "scheduler"

autoModeConfig:
  enabled: true

下記 ConfigMap の追加から始めます。

apiVersion: v1
kind: ConfigMap
metadata:
  name: amazon-vpc-cni
  namespace: kube-system
data:
  enable-network-policy-controller: "true"

Auto Mode の場合はアドオン追加ではなく、Kubernetes リソースを追加するだけで利用できるようですね。
これなら Kubernetes バージョンアップの際は VPC CNI plugin の存在を意識する必要がありません。

コントロールプレーン操作用の権限を取得します。

aws eks update-kubeconfig --name test-cluster --region ap-northeast-1

ConfigMap の追加を行います。

kubectl apply -f configmap.yaml

続いて NodeClass を作成します。

apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: network-policy-enabled
spec:
  # Enables network policy support
  networkPolicy: DefaultAllow
  # Optional: Enables logging for network policy events
  networkPolicyEventLogs: Enabled
  # Include other Node Class configurations as needed

NodeClass は Kubernetes リソースですが、Karpenter 用の Custom Resources になります。
Karpenter はこちらの設定を元に EC2 を作成します。(EC2 特有の設定を吸収するための Custom Resource)

Node Classes enable configuration of AWS specific settings. Each NodePool must reference an EC2NodeClass using spec.template.spec.nodeClassRef. Multiple NodePools may point to the same EC2NodeClass.
NodeClasses

こういう所からも Auto Mode の裏で見えなくなっているけど動いているであろう Karpenter の存在を感じずにはいられませんね。
ただし、完全に同じ定義ではなく、apiVersioneks.amazonaws.com/v1 に変わってますのでこちらには注意が必要です。
(自分でインスタンスした Karpenter は karpenter.sh/v1)

Network Policy を試してみる

セットアップが完了したので、VPC CNI plugin が Network Policy に対応した際のブログと同様のテストを行います。

スクリーンショット 2024-12-04 18.29.57.png

https://aws.amazon.com/jp/blogs/containers/amazon-vpc-cni-now-supports-kubernetes-network-policies/

サンプルアプリをデプロイします。

% kubectl get pods --all-namespaces
NAMESPACE    NAME                        READY   STATUS    RESTARTS   AGE
another-ns   another-client-one          1/1     Running   0          4m49s
another-ns   another-client-two          1/1     Running   0          4m48s
default      client-one                  1/1     Running   0          4m50s
default      client-two                  1/1     Running   0          4m49s
default      demo-app-68798b55d6-pmktj   1/1     Running   0          4m50s

同時に Service も作成されています。

% kubectl describe service demo-app
Name:              demo-app
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=demo-app
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.100.141.119
IPs:               10.100.141.119
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         192.168.144.48:80
Session Affinity:  None
Events:            <none>

そのため、他の Pod (今回は同じ名前空間の Pod)から問題なく通信できます。

% kubectl exec -it client-one -- curl demo-app
<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to Amazon EKS!</title>
    <style>
        html {color-scheme: light dark;}
        body {width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif;}
    </style>
  </head>
  <body>
    <h1>Welcome to Amazon EKS!</h1>
    <p>If you see this page, you are able successfully access the web application as the network policy allows.</p>
    <p>For online documentation and installation instructions please refer to
      <a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-networking.html">Amazon EKS Networking</a>.<br/><br/>
      The migration guides are available at
      <a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-networking.html">Amazon EKS Network Policy Migration</a>.
    </p>
    <p><em>Thank you for using Amazon EKS.</em></p>
</body>
</html>

次にインバウンド通信を全て拒否する NetworkPolicy を demo-app を指定して作成します。

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: demo-app-deny-all
spec:
  podSelector:
    matchLabels:
      app: demo-app
  policyTypes:
  - Ingress

Kubernetes 公式ドキュメントで言う所の Default deny all ingress traffic に相当するルールですね。

You can create a "default" ingress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any ingress traffic to those pods.
Default deny all ingress traffic

明示的な Deny は定義していないですが、Ingress のルールを指定していないので、通信できなくなります。

% kubectl exec -it client-one -- curl demo-app
curl: (28) Failed to connect to demo-app port 80 after 130511 ms: Could not connect to server
command terminated with exit code 28

実際に試してみると接続失敗してますね!
上手く Network Policy が効いているようです。

次に client-one からの接続のみの通信を明確に許可した Network Policy を作成します。

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: demo-app-allow-samens-client-one
spec:
  podSelector:
    matchLabels:
      app: demo-app
  ingress:
  - from:
      - podSelector:
          matchLabels:
            app: client-one

この状態だと、2 つの Network Policy が存在する状況です。

% kubectl get networkpolicy
NAME                               POD-SELECTOR   AGE
demo-app-allow-samens-client-one   app=demo-app   46s
demo-app-deny-all                  app=demo-app   7m41s

もう一度接続を試行すると、Pod 間通信が通りました。

% kubectl exec -it client-one -- curl demo-app
<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to Amazon EKS!</title>
    <style>
        html {color-scheme: light dark;}
        body {width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif;}
    </style>
  </head>
  <body>
    <h1>Welcome to Amazon EKS!</h1>
    <p>If you see this page, you are able successfully access the web application as the network policy allows.</p>
    <p>For online documentation and installation instructions please refer to
      <a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-networking.html">Amazon EKS Networking</a>.<br/><br/>
      The migration guides are available at
      <a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-networking.html">Amazon EKS Network Policy Migration</a>.
    </p>
    <p><em>Thank you for using Amazon EKS.</em></p>
</body>
</html>

元々デフォルトで Deny するだけなので、明示的に通信を許可して上げれば Pod 間通信が通る形です。
何はともあれ、アドオン無しで良い感じに Network Policy が使えています!

まとめ

Network Policy は様々なワークロードで利用が想定されますし、使うか使わないかは置いておいて、複雑な設定無しで気軽に使えた方が良いよなぁと思っていました。
今回のアップデートでより、EKS ならではのセットアップ手順や EKS バージョンアップデート時の手間を低減できるようになったのでとても嬉しいです。
是非、より楽かつセキュアに EKS を使いこなしていきましょう!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.